package com.platform.comm.util;

import cn.hutool.core.lang.UUID;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
 * Description: 对锁进行封装
 *
 * @author zyk
 */
@Slf4j
@Component
public class RedisLockUtil {

    @Value("${lock.expire_time: 100000}")
    private int lockExpireTime;
    @Value("${lock.retry_interval_time: 5000}")
    private int lockRetryTime;
    @Value("${lock.retry_times: 3}")
    private int retryTimes;

    @Autowired
    private RedisLocker redisLocker;

    public Lock tryLock(String lockKey){
        String requestId = UUID.fastUUID().toString();
        boolean getLock = lock(lockKey, requestId,  retryTimes, lockExpireTime,  lockRetryTime);
        return new Lock(lockKey,requestId,getLock);
    }

    public boolean unlock(Lock lock){
        return unlock(lock.getLockKey(), lock.getRequestId());
    }

    /**
     *
     * @param lockKey 锁key
     * @param requestId 请求锁id
     * @param retryTimes 重试次数
     * @param lockExpireTime 过期时间
     * @param lockRetryTime 重试间隔
     * @return 当加锁成功返回true，否则返回false
     */
    public boolean lock(String lockKey, String requestId, int retryTimes,int lockExpireTime, int lockRetryTime) {
        boolean isContinue = true;
        boolean isGetLock = false;
        int count = 0;
        try {
            while (isContinue) {
                if (!redisLocker.tryLock(lockKey, requestId, lockExpireTime)) {
                    count++;
                    Thread.sleep(lockRetryTime);
                    if (count > retryTimes) {
                        isContinue = false;
                    }
                } else {
                    isContinue = false;
                    isGetLock = true;
                }
            }
        } catch (InterruptedException e) {
            log.error("tryLock is error:", e);
            // Restore interrupted state...
            Thread.currentThread().interrupt();
        }
        return isGetLock;
    }

    /**
     *  解锁
     * @param lockKey
     * @param requestId
     * @return
     */
    public boolean unlock(String lockKey, String requestId) {
        return redisLocker.releaseLock(lockKey, requestId);
    }


    @Data
    public static class Lock{

        private String lockKey;

        private String requestId;

        private boolean getLock;

        public Lock(String lockKey, String requestId, boolean getLock) {
            this.lockKey = lockKey;
            this.requestId = requestId;
            this.getLock = getLock;
        }
    }
}
